package com.ccteam.fluidmusic.config

import android.content.ContentResolver
import android.graphics.Point
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.LocalUriFetcher
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoaderFactory
import com.bumptech.glide.load.model.MultiModelLoaderFactory
import com.bumptech.glide.signature.ObjectKey
import com.ccteam.fluidmusic.fluidmusic.common.utils.isLocalMedia
import com.orhanobut.logger.Logger
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.nio.ByteBuffer

/**
 *
 * @author Xiaoc
 * @since 2021/1/7
 *
 * 基于[MediaStore]的专辑封面加载器
 * 由于 Android Q 以上版本的 [MediaStore.Audio.Albums.ALBUM_ART] 被废弃，无法获取专辑封面Uri
 * 所以在 Android Q 以上版本使用Glide加载器去获取封面数据，由Glide管理数据缓存
 * 继承 [ModelLoader] 加载器，期望接收 [Uri] 然后返回 [InputStream] 字节流
 * Glide支持 [java.io.InputStream] 和 [ByteBuffer]
 */
@RequiresApi(Build.VERSION_CODES.Q)
class MediaStoreAlbumArtModelLoader(
    private val contentResolver: ContentResolver
) : ModelLoader<Uri, InputStream> {

    /**
     * 构建数据加载器
     * 它将在给定模型、尺寸和选项的 ByteBuffer 未被缓存的时候做实际的解码工作
     * 它需要一个 [ObjectKey] 作为用于磁盘缓存键的一部分
     * 以及 [LocalUriFetcher] 接口，可以从我们的特定模型中建立一个 InputStream
     * 最后将 [ModelLoader.LoadData] 返回
     *
     * @see BitmapToInputStreamFetcher
     */
    override fun buildLoadData(
        model: Uri,
        width: Int,
        height: Int,
        options: Options
    ): ModelLoader.LoadData<InputStream> {
        val disCacheKey = ObjectKey(model)
        val fetcher = BitmapToInputStreamFetcher(width, height, model)
        return ModelLoader.LoadData(disCacheKey, fetcher)
    }

    /**
     * 当该Uri符合本地音乐Uri时进行处理，否则返回false
     * @see isMediaStoreAudioUri
     */
    override fun handles(model: Uri): Boolean = isMediaStoreAudioUri(model)

    /**
     * 判断是否是本地MediaStore的音频Uri
     */
    private fun isMediaStoreAudioUri(uri: Uri): Boolean {
        return uri.isLocalMedia()
    }

    /**
     * Bitmap 转 InputStream 工作
     * 在此处需要让我们需要的特定模型，此处为Bitmap，转化为Glide认可的InputStream
     */
    inner class BitmapToInputStreamFetcher(
        private val width: Int,
        private val height: Int,
        uri: Uri
    ) : LocalUriFetcher<InputStream>(contentResolver, uri) {

        override fun getDataClass(): Class<InputStream> {
            return InputStream::class.java
        }

        /**
         * 加载资源
         * 使用 [ContentResolver.loadThumbnail] 方法进行Bitmap的获取
         * 然后将其转化为 [InputStream]
         * 当出错时抛出 [FileNotFoundException] 错误
         */
        override fun loadResource(uri: Uri, contentResolver: ContentResolver): InputStream {
            val opts = Bundle(1)
            opts.putParcelable(ContentResolver.EXTRA_SIZE,Point(width,height))
            try {
                val afd = contentResolver.openTypedAssetFile(uri, "image/*", opts, null)
                afd?.let {
                    return afd.createInputStream()
                } ?: throw FileNotFoundException("该音频不存在缩略图")
            } catch (e: IOException){
                throw FileNotFoundException("该音频不存在 ${e.message}")
            }
        }

        /**
         * 当清理时，我们清除InputStream数据
         */
        override fun close(data: InputStream) {
            data.close()
        }

    }

    /**
     * 创建工厂，用于 [GlideApp] 去调用
     *
     * @see [FluidMusicGlideModule]
     */
    class BitmapToInputStreamFactory(
        private val contentResolver: ContentResolver
    ) : ModelLoaderFactory<Uri, InputStream> {


        override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<Uri, InputStream> {
            return MediaStoreAlbumArtModelLoader(contentResolver)
        }

        override fun teardown() {
            // 啥也不做
        }

    }
}